package org.kca.yarmour.data;

import java.util.*;

import org.kca.yarmour.YAException;
import org.kca.yarmour.data.GlobalData.FactionType;
import org.kca.yarmour.data.GlobalData.TerrainType;
import org.kca.yarmour.yadata.TownType;
import org.kca.yarmour.yadata.WorldLocationType;

public class WorldMap
{
    private WorldLocation[][] locations;
    private HashMap<String, Town> towns;
    private int rows, cols;
    
    public WorldMap(int r, int c)
    {
        this.rows = r;
        this.cols = c;
        towns = new HashMap<String, Town>();
    }
    
    /**
     * Gets a location at a particular position
     * @param row the row the location is in
     * @param col the column the location is in
     * @return the location at that position, or null if out of bounds
     */
    public WorldLocation getLocation(int row, int col)
    {
        if (row < 0 || row >= rows || col < 0 || col >= cols)
        {
            return null;
        }
        return locations[row][col];
    }
    
    /**
     * Gets a location at a particular position specified by a row,col string
     * @param coords the coordinates specified in row,col format. Eg. "5,6" (without quotes)
     * @return the location if it exists, or null if the coordinates are out of bounds or not
     * well specified
     */
    public WorldLocation getLocation(String coords)
    {
        String[] toks = coords.split(",");
        if (toks.length != 2) return null;
        try
        {
            int row = Integer.parseInt(toks[0]);
            int col = Integer.parseInt(toks[1]);
            return getLocation(row, col);
        }
        catch (NumberFormatException e)
        {
            return null;
        }
    }
    
    /**
     * Gets a town by id
     * @param id the id of the town
     * @return the town with that id if it exists, null otherwise
     */
    public Town getTown(String id)
    {
        return towns.get(id);
    }
    
    /**
     * Gets a collection of all towns on the map
     * @return a collection of all towns
     */
    public Collection<Town> getTowns()
    {
        return Collections.unmodifiableCollection(towns.values());
    }
    
    public void initMap(List<WorldLocationType> wlocList, List<TownType> townList)
    {
        locations = new WorldLocation[rows][cols];
        for (int i = 0; i < rows; i++)
        {
            for (int j = 0; j < cols; j++)
            {
                locations[i][j] = new WorldLocation(i, j);
                locations[i][j].setTerrain(TerrainType.FLATLAND);
            }
        }
        for (WorldLocationType wlocType : wlocList)
        {
            if (wlocType.getRow() < 0 || wlocType.getRow() >= rows || wlocType.getCol() < 0
                    || wlocType.getCol() >= cols)
            {
                throw new YAException("Invalid coordinates specified: " + wlocType.getRow() + "," +
                        wlocType.getCol());
            }
            WorldLocation loc = locations[wlocType.getRow()][wlocType.getCol()];
            loc.updateFromXMLType(wlocType);
        }
        for (TownType townType : townList)
        {
            WorldLocation wloc = getLocation(townType.getRow(), townType.getCol());
            if (wloc == null)
            {
                throw new YAException("Location for town " + townType.getName() + " does not exist");
            }
            Town town = new Town(townType.getId(), townType.getName(), wloc);
            town.setFactionLevel(townType.getFactionLevel());
            town.setMechLevel(townType.getMechLevel());
            town.setTradeLevel(townType.getTradeLevel());
            town.getTroopsForHire().addAll(townType.getTroops());
            town.getVehiclesForSale().addAll(townType.getVehicles());
            wloc.setTown(town);
            towns.put(town.getId(), town);
        }
    }
    
}
